package com.julyup.core.redis;

import com.julyup.core.util.SessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * redis实现分布式锁
 *
 * @Author: zhenzhong.wang@honeywell.com
 * @Date: 2019/4/25 10:25 AM
 */
@Component
public class RedisLock {

  private static final Logger log = LoggerFactory.getLogger(RedisLock.class);

  private static final Long RELEASE_SUCCESS = 1L;

  private static RedisTemplate redisTemplate;
  private static ValueOperations valueOps;

  private static final String lockPrefix = "lock_";

  @Autowired
  public void setRedisTemplate(RedisTemplate redisTemplate) {
    RedisLock.redisTemplate = redisTemplate;
    valueOps = redisTemplate.opsForValue();
  }

  /**
   * 加锁
   *
   * @param lockKey
   * @param requestId
   * @param expireTime
   * @return
   */
  public static boolean tryLock(String lockKey, String requestId, int expireTime) {
    String key = lockPrefix + lockKey;
    if (valueOps.setIfAbsent(key, requestId, expireTime, TimeUnit.SECONDS)) {
      log.debug("key {} 加锁成功:{}", key, requestId);
      return true;
    }
    return false;
  }

  public static boolean tryLock(String lockKey, int expireTime) {
    return tryLock(lockKey, SessionUtils.getRequest().getRequestedSessionId(), expireTime);
  }

  /**
   * 释放锁
   *
   * @param lockKey
   * @param requestId
   * @return
   */
  public static boolean releaseLock(String lockKey, String requestId) {

    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    DefaultRedisScript redisScript = new DefaultRedisScript();
    redisScript.setScriptText(script);
    redisScript.setResultType(Long.class);

    String key = lockPrefix + lockKey;
    Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);

    if (RELEASE_SUCCESS.equals(result)) {
      log.debug("key {} 解锁成功", key);
      return true;
    }
    return false;
  }

  public static boolean releaseLock(String lockKey) {
    return releaseLock(lockKey, SessionUtils.getRequest().getRequestedSessionId());
  }
}
